﻿using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
using ESRI.ArcGIS.Geometry;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
using PlanningGIS.ArcGIS;
using PlanningGIS.MapSheet;
using PlanningGIS.Util.Convertor;
using PlanningGIS.Util.Log;

namespace PlanningGIS.DataConvert
{
    /// <summary>
    /// 导出cad时dwg边框处理类
    /// </summary>
    public class FrameCAD : ConvertCAD
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public FrameCAD()
        {
            XOffset = 0;
            YOffset = 0;
            Scale = 500;
            UnitValue = 1;
            SecurityLevel = "秘密";
        }

        /// <summary>
        /// 比例尺大小
        /// </summary>
        private double _Scale = 500;

        /// <summary>
        /// 获取或设置输出的比例尺大小【必需】
        /// </summary>
        [Description("获取或设置输出的比例尺大小【必需】")]
        public double Scale
        {
            get { return _Scale; }
            set
            {
                _Scale = value;
                _Ratio = _Scale / 100;
            }
        }

        #region IFrameInfo

        /// <summary>
        /// 获取或设置X的偏移量【输入，非必需】
        /// </summary>
        [Description("获取或设置X的偏移量【输入，可选】")]
        public double XOffset { get; set; }

        /// <summary>
        /// 获取或设置Y的偏移量【输入，非必需】
        /// </summary>
        [Description("获取或设置Y的偏移量【输入，可选】")]
        public double YOffset { get; set; }

        /// <summary>
        /// 获取或设置单位，默认为1000（千米）【输入，可选】
        /// </summary>
        [Description("获取或设置单位，默认为1000（千米）,不能为0【输入，可选】")]
        public int UnitValue { get; set; }

        /// <summary>
        /// 获取或设置图幅名称【输入，可选】
        /// </summary>
        [Description("获取或设置图幅名称【输入，可选】")]
        public string SheetName { get; set; }

        /// <summary>
        /// 获取或设置要导出的图号
        /// </summary>
        public string SheetCode { get; set; }

        /// <summary>
        /// 获取或设置密级
        /// </summary>
        public string SecurityLevel { get; set; }

        /// <summary>
        ///  获取或设置单位
        /// </summary>
        public string UnitName { get; set; }

        /// <summary>
        /// 获取或设置关联的九宫格的图号（或图名），从左到右、从上到下【输入，可选】
        /// </summary>
        [Description("获取或设置关联的九宫格的图号（或图名），从左到右、从上到下【输入，可选】")]
        public List<string> SheetCodes { get; set; }

        /// <summary>
        /// 左下角数据信息
        /// </summary>
        protected List<string> _LeftValues = null;

        /// <summary>
        /// 右下角数据信息
        /// </summary>
        protected List<string> _RightValues = null;
        #endregion

        /// <summary>
        /// 获取图幅经过偏移后的坐标值信息，
        /// 属性为 XMin、XMax、YMin、YMax。用来处理四个角的坐标对象
        /// </summary>
        public dynamic OffsetExtent { get; protected set; }

        /// <summary>
        /// 要导出的范围【输入，必需】
        /// </summary>
        public IEnvelope InnerExtent { get; set; }

        /// <summary>
        /// 计算后的外边框范围
        /// </summary>
        public IEnvelope OuterExtent { get; protected set; }

        /// <summary>
        /// 毫米换算到点 2.83465
        /// </summary>
        public const double _TOPT_MM = 2.83465;

        /// <summary>
        /// 英寸换算到点 72
        /// </summary>
        public const double _TOPT_IN = 72;

        /// <summary>
        /// 内外边框的距离 1.2 = 1.1+0.1 间隔+宽度
        /// </summary>
        public const double _INNER_DIS = 1.2;

        /// <summary>
        /// 与标准图廓出图的单位比率
        /// </summary>
        private double _Ratio = 1;

        /// <summary>
        /// 图层名称
        /// </summary>
        protected string _LayerName = "";

        /// <summary>
        /// 图廓是否已经存在
        /// </summary>
        private bool _HasTK = false;

        /// <summary>
        /// 创建标准图幅对象
        /// </summary>
        /// <param name="envelope"></param>
        /// <param name="hastk"></param>
        public void DrawSheet(IEnvelope envelope, bool hastk = false)
        {
            _LayerName = CreateCadLayer("TK");
            InnerExtent = envelope;
            _HasTK = hastk;
            this.OuterExtent = new Envelope()
            {
                XMin = InnerExtent.XMin - _INNER_DIS,
                XMax = InnerExtent.XMax + _INNER_DIS,
                YMin = InnerExtent.YMin - _INNER_DIS,
                YMax = InnerExtent.YMax + _INNER_DIS
            } as IEnvelope;
            OffsetExtent = new ExpandoObject();
            OffsetExtent.XMin = Math.Round((InnerExtent.XMin - XOffset) / UnitValue, 2);
            OffsetExtent.XMax = Math.Round((InnerExtent.XMax - XOffset) / UnitValue, 2);
            OffsetExtent.YMin = Math.Round((InnerExtent.YMin - YOffset) / UnitValue, 2);
            OffsetExtent.YMax = Math.Round((InnerExtent.YMax - YOffset) / UnitValue, 2);
            DrawFrame();
            DrawCrosses();
            DrawCodes();
            DrawBottomMeta(InnerExtent.XMin, InnerExtent.YMin - (_INNER_DIS + 0.3) * _Ratio, _LeftValues);
            DrawBottomMeta(InnerExtent.XMax - 9 * _Ratio, InnerExtent.YMin - (_INNER_DIS + 0.3) * _Ratio, _RightValues);
        }

        /// <summary>
        /// 绘制框架（图廓线、密级、图阔角点、标题）
        /// </summary>
        private void DrawFrame()
        {
            if (!_HasTK)//图廓线
            {
                Polyline2CadPolyline(InnerExtent.XMin - _INNER_DIS * _Ratio, InnerExtent.YMin, InnerExtent.XMax + _INNER_DIS * _Ratio, InnerExtent.YMin, _LayerName, ""); //下
                Polyline2CadPolyline(InnerExtent.XMin - _INNER_DIS * _Ratio, InnerExtent.YMax, InnerExtent.XMax + _INNER_DIS * _Ratio, InnerExtent.YMax, _LayerName, ""); //上
                Polyline2CadPolyline(InnerExtent.XMin, InnerExtent.YMin - _INNER_DIS * _Ratio, InnerExtent.XMin, InnerExtent.YMax + _INNER_DIS * _Ratio, _LayerName, ""); //左
                Polyline2CadPolyline(InnerExtent.XMax, InnerExtent.YMin - _INNER_DIS * _Ratio, InnerExtent.XMax, InnerExtent.YMax + _INNER_DIS * _Ratio, _LayerName, ""); //右

                Polyline2CadPolyline(InnerExtent.XMin - _INNER_DIS * _Ratio, InnerExtent.YMin - _INNER_DIS * _Ratio, InnerExtent.XMin - _INNER_DIS * _Ratio, InnerExtent.YMax + _INNER_DIS * _Ratio, _LayerName, ""); //下
                Polyline2CadPolyline(InnerExtent.XMin - _INNER_DIS * _Ratio, InnerExtent.YMax + _INNER_DIS * _Ratio, InnerExtent.XMax + _INNER_DIS * _Ratio, InnerExtent.YMax + _INNER_DIS * _Ratio, _LayerName, ""); //上
                Polyline2CadPolyline(InnerExtent.XMax + _INNER_DIS * _Ratio, InnerExtent.YMax + _INNER_DIS * _Ratio, InnerExtent.XMax + _INNER_DIS * _Ratio, InnerExtent.YMin - _INNER_DIS * _Ratio, _LayerName, ""); //左
                Polyline2CadPolyline(InnerExtent.XMax + _INNER_DIS * _Ratio, InnerExtent.YMin - _INNER_DIS * _Ratio, InnerExtent.XMin - _INNER_DIS * _Ratio, InnerExtent.YMin - _INNER_DIS * _Ratio, _LayerName, ""); //右
            }            
            //密级
            if (!string.IsNullOrWhiteSpace(SecurityLevel) && !_HasTK)
                Text2CadText(SecurityLevel, InnerExtent.XMax, InnerExtent.YMax + (0.5 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentRight, _LayerName, 0.3 * _Ratio, "");
            //图阔角点
            double fontsize = 0.3 * _Ratio;
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.XMin), 2).ToString(), InnerExtent.XMin, InnerExtent.YMin - (_INNER_DIS - 0.15) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.YMin), 2).ToString(), InnerExtent.XMin - (_INNER_DIS - 0.15) * _Ratio, InnerExtent.YMin + 0.15 * _Ratio, AcAlignment.acAlignmentLeft, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.XMin), 2).ToString(), InnerExtent.XMin, InnerExtent.YMax + (_INNER_DIS - 0.15) * _Ratio, AcAlignment.acAlignmentTopCenter, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.YMax), 2).ToString(), InnerExtent.XMin - (_INNER_DIS - 0.15) * _Ratio, InnerExtent.YMax + 0.15 * _Ratio, AcAlignment.acAlignmentLeft, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.XMax), 2).ToString(), InnerExtent.XMax, InnerExtent.YMax + (_INNER_DIS - 0.15) * _Ratio, AcAlignment.acAlignmentTopCenter, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.YMax), 2).ToString(), InnerExtent.XMax + (_INNER_DIS - 0.15) * _Ratio, InnerExtent.YMax + 0.15 * _Ratio, AcAlignment.acAlignmentRight, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.XMax), 2).ToString(), InnerExtent.XMax, InnerExtent.YMin - (_INNER_DIS - 0.15) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, fontsize, "");
            Text2CadText(ObjectConvertor.ToString(((double)OffsetExtent.YMin), 2).ToString(), InnerExtent.XMax + (_INNER_DIS - 0.15) * _Ratio, InnerExtent.YMin + 0.15 * _Ratio, AcAlignment.acAlignmentRight, _LayerName, fontsize, "");
            //标题
            Text2CadText(SheetCode, InnerExtent.XMin + InnerExtent.Width / 2.0, InnerExtent.YMax + (_INNER_DIS + 0.5) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, 0.5 * _Ratio, "");
            if (!string.IsNullOrWhiteSpace(SheetName))
                Text2CadText(SheetName, InnerExtent.XMin + InnerExtent.Width / 2.0, InnerExtent.YMax + (_INNER_DIS + 1.3) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, 0.6 * _Ratio, "");
            //比例尺
            Text2CadText("1:" + Scale.ToString(), InnerExtent.XMin + InnerExtent.Width / 2.0, InnerExtent.YMin - (_INNER_DIS + 0.5) * _Ratio, AcAlignment.acAlignmentTopCenter, _LayerName, 0.4 * _Ratio, "");
            //单位名称
            if (!string.IsNullOrWhiteSpace(UnitName) && !_HasTK)
            {
                string str = "";
                int len = 0;
                foreach (char c in UnitName)
                {
                    if (str == "") str = c.ToString();
                    else str = str + "\\P" + c;                        
                    len++;
                }
                Text2CadMText(str, InnerExtent.XMin - (_INNER_DIS + 0.4) * _Ratio, InnerExtent.YMin + len * 0.6 * _Ratio, AcAttachmentPoint.acAttachmentPointBottomLeft, _LayerName, 0.4 * _Ratio, 0.4 * _Ratio, "");
            }
        }

        /// <summary>
        /// 绘制横向、纵向网线十字叉及短线
        /// </summary>
        private void DrawCrosses()
        {
            if (_HasTK) return;
            int iCrossW = (Convert.ToInt32(InnerExtent.Width * 10 / Scale)) - 1;
            int iCrossH = (Convert.ToInt32(InnerExtent.Height * 10 / Scale)) - 1;
            double len = 10 * _Ratio;
            double clen = 0.5 * _Ratio;
            //生成网线十字叉
            for (int i = 1; i <= iCrossW; i++)
            {
                double x0 = InnerExtent.XMin + i * len;
                for (int j = 1; j <= iCrossH; j++)
                {
                    double y0 = InnerExtent.YMin + j * len;
                    Polyline2CadPolyline(x0 - clen, y0, x0 + clen, y0, _LayerName, "");
                    Polyline2CadPolyline(x0, y0 - clen, x0, y0 + clen, _LayerName, "");
                }
            }

            //生成坐标网线短线
            for (int i = 1; i <= iCrossH; i++)
            {
                double y0 = InnerExtent.YMin + i * len;
                Polyline2CadPolyline(InnerExtent.XMin, y0, InnerExtent.XMin + clen, y0, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMax - clen, y0, InnerExtent.XMax, y0, _LayerName, "");
            }

            for (int i = 1; i <= iCrossW; i++)
            {
                double x0 = InnerExtent.XMin + i * len;
                Polyline2CadPolyline(x0, InnerExtent.YMin, x0, InnerExtent.YMin + clen, _LayerName, "");
                Polyline2CadPolyline(x0, InnerExtent.YMax, x0, InnerExtent.YMax - clen, _LayerName, "");
            }
        }

        /// <summary>
        /// 绘制左上角图幅标识（九宫格）
        /// </summary>
        private void DrawCodes()
        {
            if (!_HasTK)
            {
                Polyline2CadPolyline(InnerExtent.XMin, InnerExtent.YMax + (0.3 + _INNER_DIS) * _Ratio, InnerExtent.XMin, InnerExtent.YMax + (0.3 + 2.4 + _INNER_DIS) * _Ratio, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMin, InnerExtent.YMax + (0.3 + 2.4 + _INNER_DIS) * _Ratio, InnerExtent.XMin + 4.5 * _Ratio, InnerExtent.YMax + (0.3 + 2.4 + _INNER_DIS) * _Ratio, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMin + 4.5 * _Ratio, InnerExtent.YMax + (0.3 + 2.4 + _INNER_DIS) * _Ratio, InnerExtent.XMin + 4.5 * _Ratio, InnerExtent.YMax + (0.3 + _INNER_DIS) * _Ratio, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMin + 4.5 * _Ratio, InnerExtent.YMax + (0.3 + _INNER_DIS) * _Ratio, InnerExtent.XMin, InnerExtent.YMax + (0.3 + _INNER_DIS) * _Ratio, _LayerName, "");

                Polyline2CadPolyline(InnerExtent.XMin, InnerExtent.YMax + (0.3 + 0.8 + _INNER_DIS) * _Ratio, InnerExtent.XMin + 4.5 * _Ratio, InnerExtent.YMax + (0.3 + 0.8 + _INNER_DIS) * _Ratio, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMin, InnerExtent.YMax + (0.3 + 1.6 + _INNER_DIS) * _Ratio, InnerExtent.XMin + 4.5 * _Ratio, InnerExtent.YMax + (0.3 + 1.6 + _INNER_DIS) * _Ratio, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMin + 1.5 * _Ratio, InnerExtent.YMax + (0.3 + _INNER_DIS) * _Ratio, InnerExtent.XMin + 1.5 * _Ratio, InnerExtent.YMax + (0.3 + 2.4 + _INNER_DIS) * _Ratio, _LayerName, "");
                Polyline2CadPolyline(InnerExtent.XMin + 3.0 * _Ratio, InnerExtent.YMax + (0.3 + _INNER_DIS) * _Ratio, InnerExtent.XMin + 3.0 * _Ratio, InnerExtent.YMax + (0.3 + 2.4 + _INNER_DIS) * _Ratio, _LayerName, "");
            }
            if (SheetCodes == null || SheetCodes.Count == 0) return;
            double height = (0.2 * _Ratio);
            foreach (string s in SheetCodes)
            {
                string[] cs = s.Split(':');
                if (cs == null || cs.Length != 2) continue;
                if(cs[0].Equals(SheetHelper.F_LeftIn))
                    Text2CadText(cs[1], InnerExtent.XMin + 0.75 * _Ratio, InnerExtent.YMax + (0.3 + 1.2 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if(cs[0].Equals(SheetHelper.F_LeftTop))
                    Text2CadText(cs[1], InnerExtent.XMin + 0.75 * _Ratio, InnerExtent.YMax + (0.3 + 2 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if(cs[0].Equals(SheetHelper.F_LeftUnder))
                    Text2CadText(cs[1], InnerExtent.XMin + 0.75 * _Ratio, InnerExtent.YMax + (0.3 + 0.4 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if(cs[0].Equals(SheetHelper.F_RightIn))
                    Text2CadText(cs[1], InnerExtent.XMin + 3.75 * _Ratio, InnerExtent.YMax + (0.3 + 1.2 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if (cs[0].Equals(SheetHelper.F_RightTop))
                    Text2CadText(cs[1], InnerExtent.XMin + 3.75 * _Ratio, InnerExtent.YMax + (0.3 + 2 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if (cs[0].Equals(SheetHelper.F_RightUnder))
                    Text2CadText(cs[1], InnerExtent.XMin + 3.75 * _Ratio, InnerExtent.YMax + (0.3 + 0.4 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if (cs[0].Equals(SheetHelper.F_TopIn))
                    Text2CadText(cs[1], InnerExtent.XMin + 2.25 * _Ratio, InnerExtent.YMax + (0.3 + 2 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
                if (cs[0].Equals(SheetHelper.F_UnderIn))
                    Text2CadText(cs[1], InnerExtent.XMin + 2.25 * _Ratio, InnerExtent.YMax + (0.3 + 0.4 + _INNER_DIS) * _Ratio, AcAlignment.acAlignmentCenter, _LayerName, height, "");
            }
            
        }

        /// <summary>
        /// 绘制底部的元数据信息
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="values"></param>
        private void DrawBottomMeta(double x, double y, List<string> values)
        {
            if (values == null || values.Count == 0) return;
            double height = (0.3 * _Ratio);
            foreach (string value in values)
            {
                Text2CadText(value, x, y, AcAlignment.acAlignmentTopLeft,_LayerName, height, "");
                y -= height + 0.2 * _Ratio;
            }
        }


    }
}
